`timescale 1ns/1ns

/***************************************RAM*****************************************/
module dual_port_RAM #(parameter DEPTH = 16,
                       parameter WIDTH = 8)(
           input wclk
           , input wenc
           , input [$clog2(DEPTH) - 1: 0] waddr  //深度对2取对数，得到地址的位宽。
           , input [WIDTH - 1: 0] wdata      	//数据写入
           , input rclk
           , input renc
           , input [$clog2(DEPTH) - 1: 0] raddr  //深度对2取对数，得到地址的位宽。
           , output reg [WIDTH - 1: 0] rdata 		//数据输出
       );

reg [WIDTH - 1: 0] RAM_MEM [0: DEPTH - 1];

always @(posedge wclk)
	begin
		if (wenc)
			RAM_MEM[waddr] <= wdata;
	end

always @(posedge rclk)
	begin
		if (renc)
			rdata <= RAM_MEM[raddr];
	end

endmodule

    /***************************************AFIFO*****************************************/
    module asyn_fifo#(
        parameter	WIDTH = 8,
        parameter DEPTH = 16
    )(
        input wclk	,
        input rclk	,
        input wrstn	,
        input	rrstn	,
        input winc	,
        input rinc	,
        input [WIDTH - 1: 0]	wdata	,

        output wire	wfull	,
        output wire	rempty	,
        output wire [WIDTH - 1: 0]	rdata
    );
parameter ADDR_WIDTH = $clog2(DEPTH);
/***************************************Bin Logic*****************************************/
reg [ADDR_WIDTH: 0] wptr_bin;
reg [ADDR_WIDTH: 0] rptr_bin;
wire [ADDR_WIDTH: 0] wptr_bin_next;
wire [ADDR_WIDTH: 0] rptr_bin_next;

// 读写指针加一条件
assign wptr_bin_next = wptr_bin + (winc & (!wfull));
assign rptr_bin_next = rptr_bin + (rinc & (!rempty));

/***************************************Gray Logic*****************************************/
reg [ADDR_WIDTH: 0] wptr_gray;
reg [ADDR_WIDTH: 0] rptr_gray;
wire [ADDR_WIDTH: 0] wptr_gray_next;
wire [ADDR_WIDTH: 0] rptr_gray_next;

// 应该用wptr_bin_next生成gray信号
assign wptr_gray_next = wptr_bin ^ (wptr_bin >> 1);
assign rptr_gray_next = rptr_bin ^ (rptr_bin >> 1);

// 赋值给下一级reg变量
always @ (posedge wclk or negedge wrstn)
	begin
		if (!wrstn)
			begin
				{wptr_bin, wptr_gray} <= 'd0;
			end
		else
			{wptr_bin, wptr_gray} <= {wptr_bin_next, wptr_gray_next};
	end

always @ (posedge rclk or negedge rrstn)
	begin
		if (!rrstn)
			begin
				{rptr_bin, rptr_gray} <= 'd0;
			end
		else
			{rptr_bin, rptr_gray} <= {rptr_bin_next, rptr_gray_next};
	end
/***************************************Full Logic*****************************************/
reg [ADDR_WIDTH: 0] rptr_gray_wr, rptr_gray_wr2;

// 判断满在写时钟域
// 打两拍
always @ (posedge wclk or negedge wrstn)
	begin
		if (!wrstn)
			begin
				{rptr_gray_wr, rptr_gray_wr2} <= 'd0;
			end
		else
			{rptr_gray_wr2, rptr_gray_wr} <= {rptr_gray_wr, rptr_gray};
	end

assign wfull = wptr_gray == {~rptr_gray_wr2[ADDR_WIDTH: ADDR_WIDTH - 1], rptr_gray_wr2[ADDR_WIDTH - 2: 0]};
/***************************************Empty Logic*****************************************/
reg [ADDR_WIDTH: 0] wptr_gray_rr, wptr_gray_rr2;
// 判断空在读时钟域
always @ (posedge rclk or negedge rrstn)
	begin
		if (!rrstn)
			begin
				{wptr_gray_rr2, wptr_gray_rr} <= 'd0;
			end
		else
			{wptr_gray_rr2, wptr_gray_rr} <= {wptr_gray_rr, wptr_gray};
	end

assign rempty = rptr_gray == wptr_gray_rr2;
/***************************************Dual RAM*****************************************/
wire wenc, renc;
wire [ADDR_WIDTH - 1: 0] raddr, waddr;

assign wenc = winc & !wfull;
assign renc = rinc & !rempty;

assign raddr = rptr_bin[ADDR_WIDTH - 1: 0];
assign waddr = wptr_bin[ADDR_WIDTH - 1: 0];

dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH))
              u_dual_port_RAM (
                  .wclk(wclk),
                  .rclk(rclk),
                  .wenc(wenc),
                  .renc(renc),
                  .raddr(raddr),
                  .waddr(waddr),
                  .wdata(wdata),
                  .rdata(rdata)
              );
/***************************************AFIFO*****************************************/
endmodule
